#pragma once

#include <iostream>
#include <cerrno>
#include "Connection.hpp"
#include "Protocol.hpp"
#include "Calculate.hpp"
#include "Log.hpp"

using namespace Protocol;
using namespace CalCulateNS;

const static int buffer_size = 1024;

class HandlerConnection
{
public:
    static void HandlerRequest(Connection *conn)
    {
        std::string &inbuffer = conn->InBuffer();
        std::string message; // 表示一个符合协议的一个完整的报文
        Calculate calulate;  // 负责业务处理
        Factory factory;
        auto req = factory.BuildRequest();
        // 1. 明确报文边界，解决粘报问题
        while (Decode(inbuffer, &message))
        {
            // message 一定是一个完整的报文，符合协议的！
            // 2. 反序列化
            if (!req->Deserialize(message))
                continue;
            // 3. 业务处理
            auto resp = calulate.Cal(req);
            // 4. 对相应进行序列化
            std::string responseStr;
            resp->Serialize(&responseStr);
            // 5. 封装完整报文
            responseStr = Encode(responseStr);
            // 6. 将应答全部追加到outbuffer中
            conn->AddOutBuffer(responseStr);
        }
        // 考虑发送的问题了
        if (!conn->OutBufferEmpty())
        {
            conn->_sender(conn); // 对写事件，直接发！！！--- 不代表能全部发完！
        }
    }
    // 在这里读取的时候，我们关系数据是什么格式？协议是什么样子的吗？
    // 不关心！！！我们只负责把本轮属于完全读取完毕 --- 把读到的字节流数据，交给上层 --- 由上层进行分析处理
    static void Recver(Connection *conn)
    {
        errno = 0;
        // 读取流程
        char buffer[1024];
        while (true)
        {
            ssize_t n = recv(conn->SockFd(), buffer, sizeof(buffer) - 1, 0); // 非阻塞读取
            if (n > 0)
            {
                buffer[n] = 0;
                conn->AddInBuffer(buffer);
            }
            else
            {
                // std::cout << "................... errno:" << errno << std::endl;
                if (errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    // 真正的读取错误
                    conn->_excepter(conn); // 直接回调自己的异常处理就可以了！
                    return;
                }
            }
        }
        std::cout << "sockfd# " << conn->SockFd() << ":\n"
                  << conn->InBuffer() << std::endl;
        // 尝试分析处理报文 -- 半个，一个半， 10个，11个半
        HandlerRequest(conn);
    }
    static void Sender(Connection *conn)
    {
        errno = 0;
        std::string &outbuffer = conn->OutBuffer();
        while (true)
        {
            ssize_t n = send(conn->SockFd(), outbuffer.c_str(), outbuffer.size(), 0);
            if (n >= 0)
            {
                outbuffer.erase(0, n); // 已经发给OS的，就直接移除了 // conn->remove(n);
                if (outbuffer.empty())
                    break;
            }
            else
            {
                if (errno == EAGAIN)
                    break; // 只有这里，才会正常退出
                else if (errno == EINTR)
                    continue;
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }
        }

        // 走到这里，意味着什么？我们本轮发满了，但是数据可能没发完，为什么没发完呢？
        // 开启对conn->SockFd() EPOLLOUT的关心！！！！！， 如何开启对于特定一个connection对应的写事件关心呢？？？
        if (!conn->OutBufferEmpty())
        {
            conn->_R->EnableReadWrite(conn->SockFd(), true, true);
        }
        else
        {
            conn->_R->EnableReadWrite(conn->SockFd(), true, false);
        }
    }
    static void Excepter(Connection *conn)
    {
        lg.LogMessage(Info, "connection erase done, who: %d\n", conn->SockFd());
        errno = 0;
        // 从epoll中移除对conn->Sockfd的关心
        // unordered_map 移除conn
        conn->_R->RemoveConnection(conn->SockFd());
        // 关闭conn->Sockfd
        conn->Close();
        // delete conn
        delete conn;
    }
};